# -*- coding:utf-8 -*-

'''
PROJECT_NAME : auth_demo
file    : main
author  : 1032162439@qq.com
date    : 2022-09-12 20:11
IDE     : PyCharm
'''
from functools import wraps

from django.db.models import Q
from django.http import HttpResponse
from django.shortcuts import render, reverse, redirect
from django.urls import path
from types import FunctionType

from django.utils.safestring import mark_safe
from django import forms


def get_choice_text(title, field):
    """
    获取choice的选项
    title 表头
    field 字段名
    :return:
    """

    def inner(_, obj=None, is_header=None):
        if is_header:
            return title
        return getattr(obj, f'get_{field}_display')()

    return inner


class FastModelForm(forms.ModelForm):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        for field in self.fields:
            # 可以在这里定制一些样式或者其他属性
            print(field, type(field))


class FastHandler(object):

    def display_checkbox(self, obj, is_header=None):
        if is_header:
            return "选择"
        return mark_safe('<input type="checkbox" name="pk" value="%s" />' % obj.pk)

    def display_edit(self, obj=None, is_header=None):
        if is_header:
            return '编辑'
        else:
            html_tag = '<a href="%s">编辑</a>' % (
                reverse(f'{self.site.namespace}:{self.get_change_url_name}', kwargs={'pk': obj.pk}))
            return mark_safe(html_tag)

    def display_delete(self, obj=None, is_header=None):
        if is_header:
            return '删除'
        else:
            html_tag = '<a href="%s">删除</a>' % (
                reverse(f'{self.site.namespace}:{self.get_del_url_name}', kwargs={'pk': obj.pk}))
            return mark_safe(html_tag)

    list_display = []

    has_add_btn = True

    add_model_form_class = None

    order_list = []

    search_list = []

    select_list = []

    action_list = []

    per_page_count = 5

    def get_per_page_count(self) -> int:
        return self.per_page_count or 5

    def get_action_list(self):
        return self.action_list

    def action_multi_delete(self):
        pk_list = self.request.POST.getlist('pk')
        print(pk_list)
        self.model_class.objects.filter(id__in=pk_list).delete()

    action_multi_delete.text = '批量删除'

    def wrapper(self, func):
        @wraps(func)
        def inner(request, *args, **kwargs):
            self.request = request
            return func(request, *args, **kwargs)

        return inner

    def get_select_list(self):
        return self.search_list

    def get_search_list(self):
        return self.search_list

    def get_order_list(self):
        return self.order_list or ['-id']

    def get_add_model_form(self):
        if self.add_model_form_class:
            return self.add_model_form_class
        else:
            class DynamicModelForm(FastModelForm):
                class Meta:
                    model = self.model_class
                    fields = '__all__'

            return DynamicModelForm

    def get_list_display(self):
        val = []
        val.extend(self.list_display)
        return val

    def get_add_btn(self):
        if self.has_add_btn:
            html_tag = '<a class="btn btn-primary" href="%s">新增</a>' % (
                reverse(f'{self.site.namespace}:{self.get_add_url_name}'))
            return mark_safe(html_tag)

    def __init__(self, site, model_class, prefix=None):
        self.site = site
        self.model_class = model_class
        self.prefix = prefix
        self.request = None

    def changelist_view(self, request):

        ##### 批量操作 ######
        action_list = self.get_action_list()  # action_list = [StarkHandler.action_multi_delete, ]
        action_dict = {func.__name__: func.text for func in
                       action_list}  # action_dict = {'action_multi_delete': '批量删除', 'aciton_multi_init': '批量初始化'}
        if request.method == 'POST':
            action_func_name = request.POST.get('action')
            if action_func_name and action_func_name in action_dict:
                action_response = getattr(self, action_func_name)()
                if action_response:
                    return action_response

        # 获取查询数据
        search_list = self.get_search_list()
        search_value = request.GET.get('q', '')
        conn = Q()
        conn.connector = 'OR'
        if search_value:
            for item in search_list:
                conn.children.append((item, search_value))

        # 获取排序数据
        order_list = self.get_order_list()

        # 操作分页
        from ..utils.pagination import Pagination

        ####  0 获取数据库中所有数据
        query_set = self.model_class.objects.filter(conn).order_by(*order_list)

        all_count = query_set.count()

        query_params = request.GET.copy()
        query_params._mutable = True

        pager = Pagination(
            current_page=request.GET.get('page'),
            all_count=all_count,
            base_url=request.path_info,
            query_params=query_params,
            per_page=self.get_per_page_count(),
        )

        query_set = query_set[pager.start: pager.end]

        ######### 1 处理表格  ###############
        list_diaplay = self.get_list_display()
        ####  1.1 处理表头
        table_header = []
        for item in list_diaplay:
            if isinstance(item, FunctionType):
                table_header.append(item(self, obj=None, is_header=True))
            else:
                table_header.append(item)
        #### 1.2 处理表体
        table_body = []
        for item in query_set:
            row = []
            for val in list_diaplay:
                if isinstance(val, FunctionType):
                    row.append(val(self, obj=item, is_header=False))
                else:
                    row.append(getattr(item, val))
            table_body.append(row)

        ####### 2-添加新增按钮 ################
        add_btn = self.get_add_btn()

        context = {
            'table_header': table_header,
            'table_body': table_body,
            'add_btn': add_btn,
            'search_list': search_list,
            'search_value': search_value,
            'action_list': action_list,
            'action_dict': action_dict,
            'pager': pager
        }
        return render(request, 'fast/list.html', context=context)

    def add_view(self, request):
        ####### 3-添加新增表单 ################
        if request.method == 'GET':
            add_model_form = self.get_add_model_form()
            context = {
                'add_model_form': add_model_form()
            }
            return render(request, 'fast/change.html', context=context)
        add_model_form = self.get_add_model_form()(data=request.POST)
        if add_model_form.is_valid():
            add_model_form.save()
            return redirect(reverse('%s:%s' % (self.site.namespace, self.get_list_url_name)))
        else:
            return HttpResponse('failed')

    def change_view(self, request, pk):
        change_object = self.model_class.objects.filter(pk=pk).first()
        if not change_object:
            return HttpResponse('修改的数据不存在')
        add_model_class = self.get_add_model_form()
        if request.method == 'GET':
            form = add_model_class(instance=change_object)
            context = {
                'add_model_form': form
            }
            return render(request, 'fast/change.html', context=context)
        form = add_model_class(instance=change_object, data=request.POST)
        if form.is_valid():
            form.save()
            return redirect(reverse('%s:%s' % (self.site.namespace, self.get_list_url_name)))
        else:
            return HttpResponse('change failed')

    def del_view(self, request, pk):
        delete_object = self.model_class.objects.filter(pk=pk).first()
        if not delete_object:
            return HttpResponse('删除的数据不存在')
        delete_object.delete()
        return redirect(reverse('%s:%s' % (self.site.namespace, self.get_list_url_name)))

    def get_url_name(self, param):
        """
        获取url的name属性，用于方便使用name方向生成url
        :param param:
        :return:
        """
        app_label, model_name = self.model_class._meta.app_label, self.model_class._meta.model_name
        if self.prefix:
            return f'{self.prefix}_{app_label}_{model_name}_{param}'
        return f'{app_label}_{model_name}_{param}'

    @property
    def get_list_url_name(self):
        """
        获取列表url的name属性
        :return:
        """
        return self.get_url_name('list')

    @property
    def get_add_url_name(self):
        return self.get_url_name('add')

    @property
    def get_change_url_name(self):
        return self.get_url_name('change')

    @property
    def get_del_url_name(self):
        return self.get_url_name('del')

    def get_urls(self):
        patterns = []
        patterns.append(path('list/', self.wrapper(self.changelist_view), name=self.get_list_url_name))
        patterns.append(path('add/', self.wrapper(self.add_view), name=self.get_add_url_name))
        patterns.append(path('change/<pk>', self.wrapper(self.change_view), name=self.get_change_url_name))
        patterns.append(path('del/<pk>', self.wrapper(self.del_view), name=self.get_del_url_name))
        extra_urls = self.extra_urls()
        if extra_urls:
            patterns.extend(extra_urls)
        return patterns

    def extra_urls(self) -> list:
        pass

    def reverse_list_url(self):
        list_url = '%s:%s' % (self.site.namespace, self.get_list_url_name)
        if self.request.GET:
            copy_params = self.request.GET.copy()
            copy_params._mutable = True
            list_url = '%s?%s' % (list_url, copy_params.urlencode())
        return list_url

    def reverse_add_url(self):
        add_url = '%s:%s' % (self.site.namespace, self.get_add_url_name)
        if self.request.GET:
            copy_params = self.request.GET.copy()
            copy_params._mutable = True
            add_url = '%s?%s' % (add_url, copy_params.urlencode())
        return add_url


class FastSite(object):
    def __init__(self):
        self._registry = []
        self.app_name = 'faster'
        self.namespace = 'faster'

    def register(self, model_class, handler_class=None, prefix=None):
        """
        用于将模型类注册到站点,方便站点对其进行增删改查操作
        :param model_class: 模型类
        :param handler_class: 操作增删改查的类
        :return:
        """
        if not handler_class:
            handler_class = FastHandler
        self._registry.append(
            {'model_class': model_class, 'handler': handler_class(self, model_class, prefix), 'prefix': prefix})

    def get_urls(self):
        patterns = []
        for item in self._registry:
            model_class = item['model_class']
            app_label, model_name = model_class._meta.app_label, model_class._meta.model_name
            handler = item['handler']
            prefix = item['prefix']
            if prefix:
                patterns.append(path(f'{prefix}/{app_label}/{model_name}/', (handler.get_urls(), None, None)))
            else:
                patterns.append(path(f'{app_label}/{model_name}/', (handler.get_urls(), None, None)))
        return patterns

    @property
    def urls(self):
        return self.get_urls(), self.app_name, self.namespace


site = FastSite()
